package com.sduept.nwld.dataserver.manager.statistics;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.inject.Inject;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.sduept.bigdata.fault.analysis.log.FaultAnalysisLog;
import com.sduept.bigdata.fault.analysis.log.FaultHandlerLogger4DB;
import com.sduept.bigdata.fault.entity.FaultDetail;
import com.sduept.bigdata.fault.entity.FaultRecord;
import com.sduept.bigdata.fault.entity.FaultReportBreaker;
import com.sduept.bigdata.fault.entity.FaultReportMain;
import com.sduept.bigdata.fault.entity.FaultReportMainProtection;
import com.sduept.bigdata.fault.entity.FaultReportStationDetail;
import com.sduept.bigdata.fault.manager.FaultAnalysisLogManager;
import com.sduept.bigdata.fault.manager.FaultDetailManager;
import com.sduept.bigdata.fault.manager.FaultRecordQueryManager;
import com.sduept.bigdata.fault.manager.FaultReportQueryManager;
import com.sduept.message.entity.AlarmMessage;
import com.sduept.message.manager.AlarmMessageManager;
import com.sduept.nwld.dataserver.manager.config.ParamDesc;

/**
 *故障详细抽取定时任务
 */
//@Singleton
//@Startup
    @Service
public class FaultDetailExtractSchedule {

    @Inject
    private FaultRecordQueryManager frqM;
    @Inject
    private FaultDetailManager fdM;

    @Inject
    private FaultReportQueryManager faultReportQueryM;
    @Inject
    private AlarmMessageManager amM;
    @Inject
    private FaultAnalysisLogManager falM;
    



    /**
     *	 每天执行的任务，每天凌晨4点执行
     */
//    @Schedule(second = "0", minute = "0", hour = "4", persistent = false)
    @Scheduled(cron = "0 0 4  * * ?")//*/5 * * * * ?
    public void dayExecute() {
        executeDetectFaultRecord();
        executeDetectActTime();
        executeFaultDetailExtract();
    }

    /*
     * 检测三个动作时间不完善的数据  重新去抽取 没完善的加入日志 如果日志包含了这个不完善数据的日志-过
     */
    private void executeDetectActTime() {
        // TODO Auto-generated method stub
        List<FaultDetail> unFinished = fdM.getUnFinishedActTimeFaultDetailList();// 
        for (FaultDetail fd : unFinished) {
            FaultRecord  fr =  frqM.findById(fd.getFaultRecordId());
            fdM.deleteByFaultRecordId(fd.getFaultRecordId());//删除以后（大多为两个站） 重新抽取
            try {
                extractActionTime(fr);
            } catch (Exception e) {
                e.printStackTrace();
            }//挨个抽取赋值
        }
    }


    /**
     * 检测最近一个月内 故障是否有置为非故障的  如果有 删除对应的faultDetail
     */
    private void executeDetectFaultRecord() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, -1);//得到前一个月
        Date startTime = calendar.getTime();
        Date endTime = new Date();
        List<FaultRecord>  frs =  frqM.findFaultByTime(startTime, endTime);
        for (FaultRecord fr : frs) {
            if(fr.getStatus()==1) {//非故障
                fdM.deleteByFaultRecordId(fr.getId());
            }
        }
    }


    /**
     * 故障详细抽取
     * 检查前一个月的所有故障是否有置为非故障的  如果有 删除该faultDetail
     *	 检查faultDetail里 三个 动作时间不全的   不全的记到fault日志里
     *	 执行下面的操作
     *	1.按照最大时间去对应表中抽取数据
     *	2 抽取对应字段 存储到faultdetail中
     *	 3 判断三个动作时间是否都抽取成功 不成功是否要存日志或者其他提示操作
     */
    private void executeFaultDetailExtract() {
        FaultDetail fd = fdM.getMaxDateFaultDetail();
        Date startTime = fd.getFaultTime();
        Date endTime = new Date();
        List<FaultRecord>  frs =  frqM.findFaultByTime(startTime, endTime);
        organizeFaultDetail(frs);
    }

    /**
     * 根据故障信息 组织故障详细
     * @param frs
     */
    private void organizeFaultDetail(List<FaultRecord> frs) {
        if(CollectionUtils.isEmpty(frs)) {
            return ;
        }
        for (FaultRecord fr : frs) {
            if(fr.getVoltage()==null||fr.getVoltage()!=500) {
                continue;
            }
            try {
                extractActionTime(fr);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 抽取保护动作时间
     * @param frm
     * @param fd
     * @throws Exception
     */
    private void extractActionTime(FaultRecord fr) throws Exception {
        FaultReportMain  frm = faultReportQueryM.getFaultReportMain(fr.getId());
        if(frm==null) {//生成FaultDetail 并写入日志 完善该故障的信息
            FaultDetail fd = createFaultDetail(fr,null);
            fd.setStationName(fr.getStationName());
            fdM.createOrUpdate(fd);
            writeLogAndCreateAlarmMessage(fd);
            return;
        }
        Set<FaultReportStationDetail>  stationDetail = frm.getFaultReportStationDetails();
        for (FaultReportStationDetail sd : stationDetail) {
            Set<FaultReportBreaker>  breakerS = sd.getFaultReportBreakerActions();//断路器动作时间
            Set<FaultReportMainProtection> protectionActTime = sd.getFaultReportMainProtectionActions();//保护动作时间
            FaultDetail fd = createFaultDetail(fr,sd);
            fd.setQuickProtectStatus(sd.getRapidProtection());
            fd.setReclosingStatus(sd.getReclosingSuccess());
            fd.setStationName(sd.getStationName());
            Float faultContinueTime =   getFaultContinueTime( sd.getFirstFault()) ;
            Float breakerActTime = getFaultBreakerActTime(breakerS);
            Float protectActTime = getFaultProtectActTime(protectionActTime);
            fd.setBreakerActionTime(breakerActTime);
            fd.setFaultContinueTime(faultContinueTime);
            fd.setPrimaryProtectTime(protectActTime);
            fdM.createOrUpdate(fd);
            if(!iscompleteActTime(fd)) {//判断  不完善写入日志
            	writeLogAndCreateAlarmMessage(fd);
            };
        }
    }

    /**
     * 写入日志
     * @param fd
     */
    private void writeLogAndCreateAlarmMessage(FaultDetail fd) {
        // TODO Auto-generated method stub
    	List<FaultAnalysisLog> fals = falM.getAnalysisLogBySourceId(fd.getFaultRecordId());
    	for (FaultAnalysisLog faultAnalysisLog : fals) {
    		if("动作时间检查".equals(faultAnalysisLog.getItem())) {
    			return;
    		}
		}
        FaultHandlerLogger4DB flog = new FaultHandlerLogger4DB();
        StringBuilder build = new StringBuilder();
        build.append("故障动作时间检查：故障时间："+fd.getFaultTime()+" 故障设备："+fd.getFaultEquipment()+"该故障动作时间抽取不完整或者动作时间不准确;");
        flog.log(null, 1, fd.getFaultRecordId(), "动作时间检查", 0,build.toString());
        createAlarmMessage(fd,build.toString());
    }

      /**
       * 异常告警
     * @param string 
     * @param fd 
       */
    private void createAlarmMessage(FaultDetail fd, String content) {
    	List<AlarmMessage> alas = amM.findAlarmBySource(fd.getId());
    	if(CollectionUtils.isNotEmpty(alas)) {
    		return;
    	}
    	AlarmMessage ala = new AlarmMessage();
    	ala.setCreateTime(new Date());
    	ala.setContent(content);
    	ala.setMsgType("xtyc");
    	ala.setSource(fd.getId());
    	ala.setStatus(0);
    	ala.setTimeliness(864000000);
    	amM.createOrUpdate(ala);
	}


	/**
     * 判断故障详细里的三个动作时间是否完成
     * @param fd
     * @return
     */
    private boolean iscompleteActTime(FaultDetail fd) {
        if((fd.getBreakerActionTime()==null||fd.getBreakerActionTime()==0)
        		||(fd.getFaultContinueTime()==null||fd.getFaultContinueTime()==0)
        		||(fd.getPrimaryProtectTime()==null||fd.getPrimaryProtectTime()==0)) {
            return false;
        }else {
            return true;
        }
    }


    /**
     * 保护动作时间
     * @param protectionActTime
     * @return
     */
    private Float getFaultProtectActTime(Set<FaultReportMainProtection> protectionActTime) {
        Float protectActTime = null;
        List<Integer> times = new ArrayList<>();
        for (FaultReportMainProtection frb : protectionActTime) {
            if("trip".equals(frb.getActionType())) {
                times.add(frb.getDistance0MomentsTime());
            }
        }
        if(times.size()>0) {
            protectActTime = 0f;
            for (Integer time : times) {
                protectActTime = protectActTime>time?protectActTime:time;
            }
            protectActTime = protectActTime/1000;
            if(protectActTime <=0||protectActTime>100 ) { 
            	return null;
            }
            return protectActTime;
        }
        return null;
    }


    /**
     * 获得断路器动作时间
     * @param breakerS
     * @return
     */
    private Float getFaultBreakerActTime(Set<FaultReportBreaker> breakerS) {
        Float breakerActTime = null;
        List<Integer> times = new ArrayList<>();
        for (FaultReportBreaker frb : breakerS) {
            if("trip".equals(frb.getActionType())) {
                times.add(frb.getDistance0MomentsTime());
            }
        }
        if(times.size()>0) {
            breakerActTime = 0f;
            for (Integer time : times) {
                breakerActTime = breakerActTime>time?breakerActTime:time;
            }
            breakerActTime = breakerActTime/1000;
            if(breakerActTime<10||breakerActTime>100) {
            	return null;
            }
            return breakerActTime;
        }
        return null;
    }

    /**
     *
     * @param firstFault
     */
    private Float getFaultContinueTime(Integer firstFault) {
        // TODO Auto-generated method stub
        if(firstFault == null||firstFault==0) {
            return null;
        }
        Float value = ((float) (firstFault/1000));
        if(value>200 || value<10) {
        	return null;
        }
        return value;
    }


    /**
     *
     * @param fr
     * @param sd 
     * @throws ParseException
     */
    private FaultDetail createFaultDetail(FaultRecord fr, FaultReportStationDetail sd) throws ParseException {
        // TODO Auto-generated method stub
    	FaultDetail fd = new FaultDetail();
    	if(sd!=null) {
    		fd = fdM.getFaultDetailByFaultIdAndStation(sd.getStationName(), fr.getId());
    	}else {
    		fd = fdM.getFaultDetailByFaultIdAndStation(fr.getStationName(), fr.getId());
    	}
    	if(fd!=null) {
    		return fd;
    	}
    	fd = new FaultDetail();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(fr.getFaultTime());
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH)+1;
        Date date = sdf.parse(year+"-"+month+"-01");
        fd.setActionProcess(fr.getDescription());
        fd.setEtype(fr.getEtype());
        fd.setFaultDate(date);
        fd.setFaultEquipment(fr.getEquipment());
        fd.setFaultPhase(fr.getFaultPhase());
        fd.setFaultRecordId(fr.getId());
        fd.setFaultTime(fr.getFaultTime());
        fd.setFaultType(fr.getFaultType());
        fd.setVoltage(fr.getVoltage().floatValue());
        return fd;
    }
}
